﻿
Imports std
Imports sync_map = remotecall.rc_pac_serve.invoker_map(Of remotecall.rc_pac_serve.sync_delegate)
Imports async_map = remotecall.rc_pac_serve.invoker_map(Of remotecall.rc_pac_serve.async_delegate)

Public Class rc_pac_serve
    Private WithEvents server As tcp_pac_server(Of _true) = Nothing

    Friend Class invoker_map(Of T)
        Inherits hashmapless(Of String, T, _64, _string_to_uint32)
    End Class

    Private ReadOnly async_invokers As async_map = Nothing
    Private ReadOnly sync_invokers As sync_map = Nothing

    Public Sub New(ByVal port As Int32)
        server = New tcp_pac_server(Of _true)(port)
        async_invokers = New async_map()
        sync_invokers = New sync_map()
    End Sub

    Public Property maxConnectionCount As Int64
        Get
            Return server.maxConnectionCount
        End Get
        Set(ByVal value As Int64)
            server.maxConnectionCount = value
        End Set
    End Property

    Public Delegate Function sync_delegate(ByVal req As envelope, ByRef res As envelope) As Boolean
    Public Delegate Function async_delegate(ByVal req As envelope, ByVal res As pointer(Of envelope)) As eventComb

    Private Function register(Of T)(ByVal n As String,
                                    ByVal d As T,
                                    ByVal m As invoker_map(Of T)) As Boolean
        If isemptystring(n) OrElse d Is Nothing OrElse m Is Nothing OrElse Not m(n) Is Nothing Then
            Return False
        Else
            m(n) = d
            Return True
        End If
    End Function

    Public Function register(ByVal name As String,
                             ByVal d As _do(Of envelope, pointer(Of envelope), eventComb)) As Boolean
        If d Is Nothing Then
            Return False
        Else
            Return register(name, Function(req, res) d(req, res))
        End If
    End Function

    Public Function register(ByVal name As String,
                             ByVal d As _do(Of envelope, envelope, Boolean)) As Boolean
        If d Is Nothing Then
            Return False
        Else
            Return register(name, Function(req, ByRef res) d(req, res))
        End If
    End Function

    Public Function register(ByVal name As String,
                             ByVal d As sync_delegate) As Boolean
        Return register(name, d, sync_invokers)
    End Function

    Public Function register(ByVal name As String,
                             ByVal d As async_delegate) As Boolean
        Return register(name, d, async_invokers)
    End Function

    Private Function async(ByVal cmd As String,
                           ByVal req As envelope,
                           ByVal res As pointer(Of envelope),
                           ByRef ec As eventComb) As Boolean
        Dim d As async_delegate = Nothing
        d = async_invokers(cmd)
        If d Is Nothing Then
            Return False
        Else
            ec = eventComb.return(Function() d(req, res))
            Return True
        End If
    End Function

    Private Function sync(ByVal cmd As String,
                          ByVal req As envelope,
                          ByRef res As envelope,
                          ByRef result As Boolean) As Boolean
        Dim d As sync_delegate = Nothing
        d = sync_invokers(cmd)
        If d Is Nothing Then
            Return False
        Else
            Dim r As envelope = Nothing
            result = do_(Function() As Boolean
                             Return d(req, r)
                         End Function,
                       False) AndAlso
                     eva(res, r)
            Return True
        End If
    End Function

    Private Function sync(ByVal cmd As String,
                          ByVal req As envelope,
                          ByVal res As pointer(Of envelope),
                          ByRef result As Boolean) As Boolean
        Dim r As envelope = Nothing
        Return sync(cmd, req, r, result) AndAlso eva(res, r)
    End Function

    Private Function create_response(ByVal result As Boolean, ByVal o As pointer(Of envelope)) As response
        If result Then
            Return New response(True, True, +o)
        Else
            Return New response(True, False)
        End If
    End Function

    Private Function invoke(ByVal req As request, ByVal res As pointer(Of response)) As eventComb
        assert(Not req Is Nothing)
        assert(Not isemptystring(req.command))
        Dim ec As eventComb = Nothing
        Dim o As pointer(Of envelope) = Nothing
        o = New pointer(Of envelope)()
        If async(req.command, req.argument, o, ec) Then
            Return New eventComb(Function() As Boolean
                                     Return waitfor(ec) AndAlso goto_next()
                                 End Function,
                                 Function() As Boolean
                                     Return eva(res, create_response(ec.end_result(), o)) AndAlso
                                            goto_end()
                                 End Function)
        Else
            Dim result As Boolean = False
            If sync(req.command, req.argument, o, result) Then
                eva(res, create_response(result, o))
            Else
                eva(res, New response(False))
            End If
            Return eventComb.succeeded()
        End If
    End Function

    Private Function invoke(ByVal input As envelope, ByVal output As pointer(Of envelope)) As eventComb
        Dim req As request = Nothing
        If unpack_request(input, req) Then
            Dim ec As eventComb = Nothing
            Dim res As pointer(Of response) = Nothing
            res = New pointer(Of response)()
            ec = invoke(req, res)
            Return New eventComb(Function() As Boolean
                                     Return waitfor(ec) AndAlso goto_next()
                                 End Function,
                                 Function() As Boolean
                                     Return ec.end_result() AndAlso
                                            pack_response(+res, output) AndAlso
                                            goto_end()
                                 End Function)
        Else
            Return eventComb.failed()
        End If
    End Function

    Private Sub server_receive_async(ByVal input() As Byte,
                                     ByVal output As pointer(Of bytes),
                                     ByRef ec As eventComb) Handles server.receive_async
        tcp_pac_extensions.receive_async(input, output, ec,
                                         Function(ByRef i As envelope, ByRef o As pointer(Of envelope)) As eventComb
                                             Return invoke(i, o)
                                         End Function)
    End Sub

    Private Sub server_receive_sync(ByVal input() As Byte,
                                    ByRef output() As Byte,
                                    ByRef result As Boolean) Handles server.receive_sync
        assert(False)
    End Sub
End Class
